--[[
Title: Request
Author(s):  wxa
Date: 2021-06-23
Desc: Request
use the lib:
------------------------------------------------------------
NPL.load("Mod/GeneralGameServerMod/Http/Request.lua");
------------------------------------------------------------
]]

local Util = import("./Util.lua");

local string_trim = commonlib.trim;
local string_lower = string.lower;
local string_upper = string.upper;

local Request = commonlib.inherit(commonlib.ToolBase);

Request:Property("Method");
Request:Property("Url");
Request:Property("Version");
Request:Property("Headers");
Request:Property("Body");

Request:Property("Params");
Request:Property("Path");
Request:Property("ContentType");

function Request:ctor()
end

function Request:Init(http_text)
    local lines = {};
	local line_pos = 0;
	local len = #http_text;

	-- parse http text to linetexts
	while (line_pos and line_pos < len) do
		local next_line_pos = string.find(http_text, "\n", line_pos + 1, true);
		local linetext = string.sub(http_text, line_pos + 1, next_line_pos);
		-- 空白行
		if (string.match(linetext, "^%s*$")) then
			table.insert(lines, next_line_pos and string.sub(http_text, next_line_pos + 1) or ""); -- body
			break;
		else
			table.insert(lines, linetext);
			line_pos = next_line_pos;
		end
	end

	-- parse first line
	local first_line_text = lines[1];
	local space_pos = 0;
	local next_space_pos = string.find(first_line_text, " ", space_pos + 1, true);
	local method = string_upper(string_trim(string.sub(first_line_text, space_pos + 1, next_space_pos), "%s"));
	space_pos = next_space_pos or (#first_line_text);
	next_space_pos = string.find(first_line_text, " ", space_pos + 1, true);
	local url = string_trim(string.sub(first_line_text, space_pos + 1, next_space_pos), "%s");
	space_pos = next_space_pos or (#first_line_text);
	next_space_pos = string.find(first_line_text, " ", space_pos + 1, true);
	local version = string_trim(string.sub(first_line_text, space_pos + 1, next_space_pos), "%s");
	self:SetMethod(method);
	self:SetUrl(url);
	self:SetVersion(version);

	-- parse headers
	local linesize = #lines;
	local headers = {};
	for i = 2, linesize - 1 do
		local header_text = lines[i];
		local split_pos = string.find(header_text, ":", 1, true);
		local key = split_pos and string.sub(header_text, 1, split_pos -1) or header_text;
		local value = split_pos and string.sub(header_text, split_pos + 1) or "";
		headers[string_lower(string_trim(key, "%s"))] = value;
	end
	self:SetHeaders(headers);

	-- parser body
	self:SetBody(linesize > 1 and lines[linesize] or "");

	-- extend path
    self:SetPath(string.gsub(self:GetUrl(), '?.*$', ''));
    self:SetContentType(self:GetHeaders()["content-type"]);
    
    -- 解析参数
    self:ParseParams();

    return self;
end

function Request:GetHeader(field)
	return self:GetHeaders()[string_lower(field)];
end

function Request:ParseParams()
	local urlArgStr = string.match(self:GetUrl(), "?(.+)$")

	if (urlArgStr) then
		self:SetParams(Util:ParseUrlArgs(urlArgStr));
	else
		self:SetParams(self:ParsePostData());
	end
end

function Request:ParsePostData()
	local params = {};
	local body = self:GetBody();
	local contentType = self:GetContentType();

	if (not contentType or not body or body == "") then return params end

	local input_type_lower = string_lower(contentType)
	if (string.find(input_type_lower, "x-www-form-urlencoded")) then
		params = Util:ParseUrlArgs(body)
	elseif (string.find(input_type_lower, "multipart/form-data")) then
		params = Util:ParseMultipartData(body, contentType, params, true);
	elseif (string.find(input_type_lower, "application/json")) then
		params = Util:FromJson(body) 
	else
		params = Util:ParseUrlArgs(body)
	end

    return params;
end

return Request;

